using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using Decav.Gatsb.Configuration;
using System.IO;
using Decav.Gatsb.Mobile;

namespace Decav.Gatsb.Application
{
    /// <summary>
    /// Parses messages on disk from SMS or MMS accounts.
    /// </summary>
    public class MessageParser
    {
        public MessageParser()
        {
        }


        private bool _loaded = false;
        private readonly object _providersSyncRoot = new object();
        private readonly Collection<TelephoneServiceProvider> _providers = new Collection<TelephoneServiceProvider>();

        /// <summary>
        /// Gets a collection of the <see cref="TelephoneServiceProvider"/> that messages
        /// can originate from.
        /// </summary>
        public Collection<TelephoneServiceProvider> Providers
        {
            get
            {
                lock (_providersSyncRoot)
                {
                    if (!_loaded)
                    {
                        foreach (MobileProviderConfiguration cfg in GatsbConfigurationSection.Current.MobileProviders)
                            _providers.Add((TelephoneServiceProvider)Activator.CreateInstance(Type.GetType(cfg.Type, true)));
                    }

                    _loaded = true;
                }

                return _providers;
            }
        }

        /// <summary>
        /// Parses a <see cref="MobileMessage"/> with the <see cref="Providers"/> and returns the message that was parsed.
        /// </summary>
        /// <param name="fileName">The file to parse the message from.</param>
        /// <returns>The <see cref="MobuleMessage"/> that the file contains.</returns>
        public MobileMessage Parse(string fileName)
        {
            if (fileName == null)
                throw new ArgumentNullException("fileName");

            using (Stream stream = new FileStream(fileName, FileMode.Open))
            using (StreamReader reader = new StreamReader(stream))
            {
                SmtpMailHeader header = SmtpMailHeader.Parse(reader);
                TelephoneServiceProvider provider = GetProvider(header);
                IPhoneMessageParser parser =  provider.CreateMessageParser();

                // Do not dispose the reader, it stupidly disposes the stream.
                return parser.ParseMailMessage(header, reader);
            }
        }

        private TelephoneServiceProvider GetProvider(SmtpMailHeader header)
        {
            foreach (TelephoneServiceProvider provider in Providers)
            {
                if (provider.IsProviderMailAddress(header.Sender.ToString()))
                    return provider;
            }

            throw new MessageSenderInvalidException(string.Format("The sender '{0}' is not valid given the currently supported providers.", header.Sender));
        }

        /// <summary>
        /// Gets the first line of a <see cref="MobileMessage"/> body.
        /// </summary>
        /// <returns>The first line of the body.</returns>
        public static string GetFirstLine(MobileMessage message)
        {
            if (message == null)
                throw new ArgumentNullException("message");


            if (string.IsNullOrEmpty(message.Body))
                return string.Empty;
            
            
            string body = message.Body.Trim();
            string[] split = body.Split(new string[] { "\r\n" }, StringSplitOptions.None); // get the first line
            return split[0].ToLower();
        }

        /// <summary>
        /// Removes message parts considered to be a part of a message history, such as a reply.
        /// </summary>
        /// <param name="message">The message to remove reply messages from.</param>
        public static void RemoveReplies(MobileMessage message)
        {
            if (message == null)
                throw new ArgumentNullException("message");

            message.Body = message.Body.Split(new string[] { "----" }, StringSplitOptions.None)[0];
        }
    }
}
